﻿using System;
using System.Threading;
using System.Net.Sockets;
using System.Collections.Generic;


namespace IveelySE.Dream.Common.Transmission
{
    internal class ServerHelper
    {
        struct ListenerAndClient
        {
            public TcpListener Listener;
            public TcpClient Client;
        }

        public delegate void ReceiveData(TcpClient client);

        public static ReceiveData delReceive = null;

        /// <summary>
        /// 客户端信息集合
        /// </summary>
        private static List<ClientInfo> ClientInfos = new List<ClientInfo>();

        private static List<TcpClient> Clients = new List<TcpClient>();

        /// <summary>
        /// 创建TCP监听
        /// </summary>
        /// <param name="port">监听端口</param>
        /// <returns></returns>
        public static TcpListener CreateTcpListener(int port)
        {
            return new TcpListener(System.Net.IPAddress.Any, port);
        }

        /// <summary>
        /// 移除客户端
        /// </summary>
        /// <param name="clients">客户端集合</param>
        /// <param name="client">需要移除的客户端</param>
        public static void RemoveClient(TcpClient client)
        {
            for (int i = 0; i < ClientInfos.Count; i++)
            {
                if (ClientInfos[i].Id == client.GetHashCode().ToString())
                {
                    Clients.Remove(client);
                    Console.WriteLine("Remove Client\t" + ClientInfos[i].IP + "\t Client List count:" + Clients.Count.ToString());
                    ClientInfos.RemoveAt(i);
                    break;
                }
            }
        }

        /// <summary>
        /// 获取连接客户端（信息）集合
        /// </summary>
        /// <returns></returns>
        public static List<ClientInfo> GetClientInfos()
        {
            return ClientInfos;
        }

        /// <summary>
        /// 获取连接客户端集合
        /// </summary>
        /// <returns></returns>
        public static List<TcpClient> GetClients()
        {
            return Clients;
        }

        /// <summary>
        /// 清空所有客户端信息集合
        /// </summary>
        public static void CleanClientInfos()
        {
            Clients.Clear();
            ClientInfos.Clear();
        }

        /// <summary>
        /// 启动监听
        /// </summary>
        /// <param name="tcpListener">TCP监听器</param>
        /// <param name="port">监听端口</param>
        public static void StartListening(ref TcpListener tcpListener, int port)
        {
            if (tcpListener != null)
            {
                tcpListener.Stop();
            }
            else
            {
                tcpListener = CreateTcpListener(port);
            }
            ListenerAndClient listemerAndClient = new ListenerAndClient();
            listemerAndClient.Listener = tcpListener;
            try
            {
                tcpListener.Start();
            }
            catch (SocketException ex)
            {
                Console.WriteLine(ex);
                return;
            }

            tcpListener.BeginAcceptTcpClient(
                new AsyncCallback(DoAcceptTcpClientCallback), listemerAndClient);
        }

        /// <summary>
        /// 关闭监听
        /// </summary>
        /// <param name="tcpListener">监听器</param>
        public static void StopListening(ref TcpListener tcpListener)
        {
            if (tcpListener != null)
            {
                tcpListener.Stop();
            }
        }

        /// <summary>
        /// 监听异步回调
        /// </summary>
        /// <param name="asyncResult"></param>
        public static void DoAcceptTcpClientCallback(IAsyncResult asyncResult)
        {
            ListenerAndClient objListenerAndClient = (ListenerAndClient)asyncResult.AsyncState;
            TcpClient client = null;

            try
            {
                client = objListenerAndClient.Listener.EndAcceptTcpClient(asyncResult);
                objListenerAndClient.Client = client;
            }
            catch (ObjectDisposedException ex)
            {
                if (objListenerAndClient.Client != null)
                {
                    objListenerAndClient.Client.Close();
                }
                return;
            }

            new ReceiveData(HandleReceive).BeginInvoke(client,
                new AsyncCallback(ReceiveCallback), objListenerAndClient.Listener);

            objListenerAndClient.Listener.BeginAcceptTcpClient(
             new AsyncCallback(DoAcceptTcpClientCallback), objListenerAndClient);
        }

        public static void HandleReceive(TcpClient client)
        {
            Console.WriteLine("Receive connect\t" + DateTime.Now.ToString() + "\t" +
            client.GetHashCode().ToString());
            ClientConnection objClientConnection = new ClientConnection(client);
            objClientConnection.OnMessageReceived += new IveelySE.Dream.Common.Transmission.ClientConnection.MessageReceive(OnReceive);
            objClientConnection.OnRemoteHostClosed += new IveelySE.Dream.Common.Transmission.ClientConnection.RemoteHostClose(OnRemoteHostClose);
            Clients.Add(client);
        }

        public static void ReceiveCallback(IAsyncResult ar)
        {

        }

        /// <summary>
        /// 服务端接收客户端信息
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="datas">数据信息</param>
        private static void OnReceive(ClientConnection sender, byte[] datas)
        {
            try
            {
                ClientInfo client = (ClientInfo)(Serializer.Deserialize(datas));
                Console.WriteLine("Receive\t\t" + DateTime.Now.ToString() + "\t" +
                    sender.Client.GetHashCode().ToString() + "\t：" + client.Information);
                ClientInfos.Add(client);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        private static void OnRemoteHostClose(ClientConnection sender)
        {
            Console.WriteLine("Remote closed\t" + DateTime.Now.ToString() + "\t" +
                sender.Client.GetHashCode());

            //Program.frmMainForm.delRemoveClient.Invoke(sender.Client);
        }
    }
}
